﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DiscoveryLogic.Common.Numeric
{
    /// <summary>
    /// This interface should be implemented by any class whose instances are intended 
    /// to be executed by a thread.
    /// </summary>
    public interface IThreadRunnable
    {
        /// <summary>
        /// This method has to be implemented in order that starting of the thread causes the object's 
        /// run method to be called in that separately executing thread.
        /// </summary>
        void Run();
    }

    public class SupportClass
    {
        /// <summary>
        /// Performs an unsigned bitwise right shift with the specified number
        /// </summary>
        /// <param name="number">Number to operate on</param>
        /// <param name="bits">Ammount of bits to shift</param>
        /// <returns>The resulting number from the shift operation</returns>
        public static int URShift(int number, int bits)
        {
            if (number >= 0)
                return number >> bits;
            else
                return (number >> bits) + (2 << ~bits);
        }

        /// <summary>
        /// Performs an unsigned bitwise right shift with the specified number
        /// </summary>
        /// <param name="number">Number to operate on</param>
        /// <param name="bits">Ammount of bits to shift</param>
        /// <returns>The resulting number from the shift operation</returns>
        public static int URShift(int number, long bits)
        {
            return URShift(number, (int)bits);
        }

        /// <summary>
        /// Performs an unsigned bitwise right shift with the specified number
        /// </summary>
        /// <param name="number">Number to operate on</param>
        /// <param name="bits">Ammount of bits to shift</param>
        /// <returns>The resulting number from the shift operation</returns>
        public static long URShift(long number, int bits)
        {
            if (number >= 0)
                return number >> bits;
            else
                return (number >> bits) + (2L << ~bits);
        }

        /// <summary>
        /// Performs an unsigned bitwise right shift with the specified number
        /// </summary>
        /// <param name="number">Number to operate on</param>
        /// <param name="bits">Ammount of bits to shift</param>
        /// <returns>The resulting number from the shift operation</returns>
        public static long URShift(long number, long bits)
        {
            return URShift(number, (int)bits);
        }

        /*******************************/
        /// <summary>
        /// Converts an array of sbytes to an array of bytes
        /// </summary>
        /// <param name="sbyteArray">The array of sbytes to be converted</param>
        /// <returns>The new array of bytes</returns>
        public static byte[] ToByteArray(sbyte[] sbyteArray)
        {
            byte[] byteArray = null;

            if (sbyteArray != null)
            {
                byteArray = new byte[sbyteArray.Length];
                for (int index = 0; index < sbyteArray.Length; index++)
                    byteArray[index] = (byte)sbyteArray[index];
            }
            return byteArray;
        }

        /// <summary>
        /// Converts a string to an array of bytes
        /// </summary>
        /// <param name="sourceString">The string to be converted</param>
        /// <returns>The new array of bytes</returns>
        public static byte[] ToByteArray(System.String sourceString)
        {
            return System.Text.UTF8Encoding.UTF8.GetBytes(sourceString);
        }

        /// <summary>
        /// Converts a array of object-type instances to a byte-type array.
        /// </summary>
        /// <param name="tempObjectArray">Array to convert.</param>
        /// <returns>An array of byte type elements.</returns>
        public static byte[] ToByteArray(System.Object[] tempObjectArray)
        {
            byte[] byteArray = null;
            if (tempObjectArray != null)
            {
                byteArray = new byte[tempObjectArray.Length];
                for (int index = 0; index < tempObjectArray.Length; index++)
                    byteArray[index] = (byte)tempObjectArray[index];
            }
            return byteArray;
        }

        /*******************************/
        /// <summary>
        /// Converts the specified collection to its string representation.
        /// </summary>
        /// <param name="c">The collection to convert to string.</param>
        /// <returns>A string representation of the specified collection.</returns>
        public static System.String CollectionToString(System.Collections.ICollection c)
        {
            System.Text.StringBuilder s = new System.Text.StringBuilder();

            if (c != null)
            {

                System.Collections.ArrayList l = new System.Collections.ArrayList(c);

                bool isDictionary = (c is System.Collections.BitArray || c is System.Collections.Hashtable || c is System.Collections.IDictionary || c is System.Collections.Specialized.NameValueCollection || (l.Count > 0 && l[0] is System.Collections.DictionaryEntry));
                for (int index = 0; index < l.Count; index++)
                {
                    if (l[index] == null)
                        s.Append("null");
                    else if (!isDictionary)
                        s.Append(l[index]);
                    else
                    {
                        isDictionary = true;
                        if (c is System.Collections.Specialized.NameValueCollection)
                            s.Append(((System.Collections.Specialized.NameValueCollection)c).GetKey(index));
                        else
                            s.Append(((System.Collections.DictionaryEntry)l[index]).Key);
                        s.Append("=");
                        if (c is System.Collections.Specialized.NameValueCollection)
                            s.Append(((System.Collections.Specialized.NameValueCollection)c).GetValues(index)[0]);
                        else
                            s.Append(((System.Collections.DictionaryEntry)l[index]).Value);

                    }
                    if (index < l.Count - 1)
                        s.Append(", ");
                }

                if (isDictionary)
                {
                    if (c is System.Collections.ArrayList)
                        isDictionary = false;
                }
                if (isDictionary)
                {
                    s.Insert(0, "{");
                    s.Append("}");
                }
                else
                {
                    s.Insert(0, "[");
                    s.Append("]");
                }
            }
            else
                s.Insert(0, "null");
            return s.ToString();
        }

        /// <summary>
        /// Tests if the specified object is a collection and converts it to its string representation.
        /// </summary>
        /// <param name="obj">The object to convert to string</param>
        /// <returns>A string representation of the specified object.</returns>
        public static System.String CollectionToString(System.Object obj)
        {
            System.String result = "";

            if (obj != null)
            {
                if (obj is System.Collections.ICollection)
                    result = CollectionToString((System.Collections.ICollection)obj);
                else
                    result = obj.ToString();
            }
            else
                result = "null";

            return result;
        }
        /*******************************/
        /// <summary>
        /// Support class used to handle threads
        /// </summary>
        public class ThreadClass : IThreadRunnable
        {
            /// <summary>
            /// The instance of System.Threading.Thread
            /// </summary>
            private System.Threading.Thread threadField;

            /// <summary>
            /// Initializes a new instance of the ThreadClass class
            /// </summary>
            public ThreadClass()
            {
                threadField = new System.Threading.Thread(new System.Threading.ThreadStart(Run));
            }

            /// <summary>
            /// Initializes a new instance of the Thread class.
            /// </summary>
            /// <param name="Name">The name of the thread</param>
            public ThreadClass(System.String Name)
            {
                threadField = new System.Threading.Thread(new System.Threading.ThreadStart(Run));
                this.Name = Name;
            }

            /// <summary>
            /// Initializes a new instance of the Thread class.
            /// </summary>
            /// <param name="Start">A ThreadStart delegate that references the methods to be invoked when this thread begins executing</param>
            public ThreadClass(System.Threading.ThreadStart Start)
            {
                threadField = new System.Threading.Thread(Start);
            }

            /// <summary>
            /// Initializes a new instance of the Thread class.
            /// </summary>
            /// <param name="Start">A ThreadStart delegate that references the methods to be invoked when this thread begins executing</param>
            /// <param name="Name">The name of the thread</param>
            public ThreadClass(System.Threading.ThreadStart Start, System.String Name)
            {
                threadField = new System.Threading.Thread(Start);
                this.Name = Name;
            }

            /// <summary>
            /// This method has no functionality unless the method is overridden
            /// </summary>
            public virtual void Run()
            {
            }

            /// <summary>
            /// Causes the operating system to change the state of the current thread instance to ThreadState.Running
            /// </summary>
            public virtual void Start()
            {
                threadField.Start();
            }

            /// <summary>
            /// Interrupts a thread that is in the WaitSleepJoin thread state
            /// </summary>
            public virtual void Interrupt()
            {
                threadField.Interrupt();
            }

            /// <summary>
            /// Gets the current thread instance
            /// </summary>
            public System.Threading.Thread Instance
            {
                get
                {
                    return threadField;
                }
                set
                {
                    threadField = value;
                }
            }

            /// <summary>
            /// Gets or sets the name of the thread
            /// </summary>
            public System.String Name
            {
                get
                {
                    return threadField.Name;
                }
                set
                {
                    if (threadField.Name == null)
                        threadField.Name = value;
                }
            }

            /// <summary>
            /// Gets or sets a value indicating the scheduling priority of a thread
            /// </summary>
            public System.Threading.ThreadPriority Priority
            {
                get
                {
                    return threadField.Priority;
                }
                set
                {
                    threadField.Priority = value;
                }
            }

            /// <summary>
            /// Gets a value indicating the execution status of the current thread
            /// </summary>
            public bool IsAlive
            {
                get
                {
                    return threadField.IsAlive;
                }
            }

            /// <summary>
            /// Gets or sets a value indicating whether or not a thread is a background thread.
            /// </summary>
            public bool IsBackground
            {
                get
                {
                    return threadField.IsBackground;
                }
                set
                {
                    threadField.IsBackground = value;
                }
            }

            /// <summary>
            /// Blocks the calling thread until a thread terminates
            /// </summary>
            public void Join()
            {
                threadField.Join();
            }

            /// <summary>
            /// Blocks the calling thread until a thread terminates or the specified time elapses
            /// </summary>
            /// <param name="MiliSeconds">Time of wait in milliseconds</param>
            public void Join(long MiliSeconds)
            {
                lock (this)
                {
                    threadField.Join(new System.TimeSpan(MiliSeconds * 10000));
                }
            }

            /// <summary>
            /// Blocks the calling thread until a thread terminates or the specified time elapses
            /// </summary>
            /// <param name="MiliSeconds">Time of wait in milliseconds</param>
            /// <param name="NanoSeconds">Time of wait in nanoseconds</param>
            public void Join(long MiliSeconds, int NanoSeconds)
            {
                lock (this)
                {
                    threadField.Join(new System.TimeSpan(MiliSeconds * 10000 + NanoSeconds * 100));
                }
            }

            /// <summary>
            /// Resumes a thread that has been suspended
            /// </summary>
            public void Resume()
            {
                threadField.Resume();
            }

            /// <summary>
            /// Raises a ThreadAbortException in the thread on which it is invoked, 
            /// to begin the process of terminating the thread. Calling this method 
            /// usually terminates the thread
            /// </summary>
            public void Abort()
            {
                threadField.Abort();
            }

            /// <summary>
            /// Raises a ThreadAbortException in the thread on which it is invoked, 
            /// to begin the process of terminating the thread while also providing
            /// exception information about the thread termination. 
            /// Calling this method usually terminates the thread.
            /// </summary>
            /// <param name="stateInfo">An object that contains application-specific information, such as state, which can be used by the thread being aborted</param>
            public void Abort(System.Object stateInfo)
            {
                lock (this)
                {
                    threadField.Abort(stateInfo);
                }
            }

            /// <summary>
            /// Suspends the thread, if the thread is already suspended it has no effect
            /// </summary>
            public void Suspend()
            {
                threadField.Suspend();
            }

            /// <summary>
            /// Obtain a String that represents the current Object
            /// </summary>
            /// <returns>A String that represents the current Object</returns>
            public override System.String ToString()
            {
                return "Thread[" + Name + "," + Priority.ToString() + "," + "" + "]";
            }

            /// <summary>
            /// Gets the currently running thread
            /// </summary>
            /// <returns>The currently running thread</returns>
            public static ThreadClass Current()
            {
                ThreadClass CurrentThread = new ThreadClass();
                CurrentThread.Instance = System.Threading.Thread.CurrentThread;
                return CurrentThread;
            }
        }


        /*******************************/
        /// <summary>
        /// This method returns the literal value received
        /// </summary>
        /// <param name="literal">The literal to return</param>
        /// <returns>The received value</returns>
        public static long Identity(long literal)
        {
            return literal;
        }

        /// <summary>
        /// This method returns the literal value received
        /// </summary>
        /// <param name="literal">The literal to return</param>
        /// <returns>The received value</returns>
        public static ulong Identity(ulong literal)
        {
            return literal;
        }

        /// <summary>
        /// This method returns the literal value received
        /// </summary>
        /// <param name="literal">The literal to return</param>
        /// <returns>The received value</returns>
        public static float Identity(float literal)
        {
            return literal;
        }

        /// <summary>
        /// This method returns the literal value received
        /// </summary>
        /// <param name="literal">The literal to return</param>
        /// <returns>The received value</returns>
        public static double Identity(double literal)
        {
            return literal;
        }

        /*******************************/
        /// <summary>
        /// This class provides auxiliar functionality to read and unread characters from a string into a buffer.
        /// </summary>
        private class BackStringReader : System.IO.StringReader
        {
            private char[] buffer;
            private int position = 1;

            /// <summary>
            /// Constructor. Calls the base constructor.
            /// </summary>
            /// <param name="stringReader">The buffer from which chars will be read.</param>
            /// <param name="size">The size of the Back buffer.</param>
            public BackStringReader(String s)
                : base(s)
            {
                this.buffer = new char[position];
            }


            /// <summary>
            /// Reads a character.
            /// </summary>
            /// <returns>The character read.</returns>
            public override int Read()
            {
                if (this.position >= 0 && this.position < this.buffer.Length)
                    return (int)this.buffer[this.position++];
                return base.Read();
            }

            /// <summary>
            /// Reads an amount of characters from the buffer and copies the values to the array passed.
            /// </summary>
            /// <param name="array">Array where the characters will be stored.</param>
            /// <param name="index">The beginning index to read.</param>
            /// <param name="count">The number of characters to read.</param>
            /// <returns>The number of characters read.</returns>
            public override int Read(char[] array, int index, int count)
            {
                int readLimit = this.buffer.Length - this.position;

                if (count <= 0)
                    return 0;

                if (readLimit > 0)
                {
                    if (count < readLimit)
                        readLimit = count;
                    System.Array.Copy(this.buffer, this.position, array, index, readLimit);
                    count -= readLimit;
                    index += readLimit;
                    this.position += readLimit;
                }

                if (count > 0)
                {
                    count = base.Read(array, index, count);
                    if (count == -1)
                    {
                        if (readLimit == 0)
                            return -1;
                        return readLimit;
                    }
                    return readLimit + count;
                }
                return readLimit;
            }

            /// <summary>
            /// Unreads a character.
            /// </summary>
            /// <param name="unReadChar">The character to be unread.</param>
            public void UnRead(int unReadChar)
            {
                this.position--;
                this.buffer[this.position] = (char)unReadChar;
            }

            /// <summary>
            /// Unreads an amount of characters by moving these to the buffer.
            /// </summary>
            /// <param name="array">The character array to be unread.</param>
            /// <param name="index">The beginning index to unread.</param>
            /// <param name="count">The number of characters to unread.</param>
            public void UnRead(char[] array, int index, int count)
            {
                this.Move(array, index, count);
            }

            /// <summary>
            /// Unreads an amount of characters by moving these to the buffer.
            /// </summary>
            /// <param name="array">The character array to be unread.</param>
            public void UnRead(char[] array)
            {
                this.Move(array, 0, array.Length - 1);
            }

            /// <summary>
            /// Moves the array of characters to the buffer.
            /// </summary>
            /// <param name="array">Array of characters to move.</param>
            /// <param name="index">Offset of the beginning.</param>
            /// <param name="count">Amount of characters to move.</param>
            private void Move(char[] array, int index, int count)
            {
                for (int arrayPosition = index + count; arrayPosition >= index; arrayPosition--)
                    this.UnRead(array[arrayPosition]);
            }
        }

        /*******************************/

        /// <summary>
        /// The StreamTokenizerSupport class takes an input stream and parses it into "tokens".
        /// The stream tokenizer can recognize identifiers, numbers, quoted strings, and various comment styles. 
        /// </summary>
        public class StreamTokenizerSupport
        {

            /// <summary>
            /// Internal constants and fields
            /// </summary>

            private const System.String TOKEN = "Token[";
            private const System.String NOTHING = "NOTHING";
            private const System.String NUMBER = "number=";
            private const System.String EOF = "EOF";
            private const System.String EOL = "EOL";
            private const System.String QUOTED = "quoted string=";
            private const System.String LINE = "], Line ";
            private const System.String DASH = "-.";
            private const System.String DOT = ".";

            private const int TT_NOTHING = -4;

            private const sbyte ORDINARYCHAR = 0x00;
            private const sbyte WORDCHAR = 0x01;
            private const sbyte WHITESPACECHAR = 0x02;
            private const sbyte COMMENTCHAR = 0x04;
            private const sbyte QUOTECHAR = 0x08;
            private const sbyte NUMBERCHAR = 0x10;

            private const int STATE_NEUTRAL = 0;
            private const int STATE_WORD = 1;
            private const int STATE_NUMBER1 = 2;
            private const int STATE_NUMBER2 = 3;
            private const int STATE_NUMBER3 = 4;
            private const int STATE_NUMBER4 = 5;
            private const int STATE_STRING = 6;
            private const int STATE_LINECOMMENT = 7;
            private const int STATE_DONE_ON_EOL = 8;

            private const int STATE_PROCEED_ON_EOL = 9;
            private const int STATE_POSSIBLEC_COMMENT = 10;
            private const int STATE_POSSIBLEC_COMMENT_END = 11;
            private const int STATE_C_COMMENT = 12;
            private const int STATE_STRING_ESCAPE_SEQ = 13;
            private const int STATE_STRING_ESCAPE_SEQ_OCTAL = 14;

            private const int STATE_DONE = 100;

            private sbyte[] attribute = new sbyte[256];
            private bool eolIsSignificant = false;
            private bool slashStarComments = false;
            private bool slashSlashComments = false;
            private bool lowerCaseMode = false;
            private bool pushedback = false;
            private int lineno = 1;

            private BackReader inReader;
            private BackStringReader inStringReader;
            private BackInputStream inStream;
            private System.Text.StringBuilder buf;


            /// <summary>
            /// Indicates that the end of the stream has been read.
            /// </summary>
            public const int TT_EOF = -1;

            /// <summary>
            /// Indicates that the end of the line has been read.
            /// </summary>
            public const int TT_EOL = '\n';

            /// <summary>
            /// Indicates that a number token has been read.
            /// </summary>
            public const int TT_NUMBER = -2;

            /// <summary>
            /// Indicates that a word token has been read.
            /// </summary>
            public const int TT_WORD = -3;

            /// <summary>
            /// If the current token is a number, this field contains the value of that number.
            /// </summary>
            public double nval;

            /// <summary>
            /// If the current token is a word token, this field contains a string giving the characters of the word 
            /// token.
            /// </summary>
            public System.String sval;

            /// <summary>
            /// After a call to the nextToken method, this field contains the type of the token just read.
            /// </summary>
            public int ttype;


            /// <summary>
            /// Internal methods
            /// </summary>

            private int read()
            {
                if (this.inReader != null)
                    return this.inReader.Read();
                else if (this.inStream != null)
                    return this.inStream.Read();
                else
                    return this.inStringReader.Read();
            }

            private void unread(int ch)
            {
                if (this.inReader != null)
                    this.inReader.UnRead(ch);
                else if (this.inStream != null)
                    this.inStream.UnRead(ch);
                else
                    this.inStringReader.UnRead(ch);
            }

            private void init()
            {
                this.buf = new System.Text.StringBuilder();
                this.ttype = StreamTokenizerSupport.TT_NOTHING;

                this.WordChars('A', 'Z');
                this.WordChars('a', 'z');
                this.WordChars(160, 255);
                this.WhitespaceChars(0x00, 0x20);
                this.CommentChar('/');
                this.QuoteChar('\'');
                this.QuoteChar('\"');
                this.ParseNumbers();
            }

            private void setAttributes(int low, int hi, sbyte attrib)
            {
                int l = System.Math.Max(0, low);
                int h = System.Math.Min(255, hi);
                for (int i = l; i <= h; i++)
                    this.attribute[i] = attrib;
            }

            private bool isWordChar(int data)
            {
                char ch = (char)data;
                return (data != -1 && (ch > 255 || this.attribute[ch] == StreamTokenizerSupport.WORDCHAR || this.attribute[ch] == StreamTokenizerSupport.NUMBERCHAR));
            }

            /// <summary>
            /// Creates a StreamToknizerSupport that parses the given string.
            /// </summary>
            /// <param name="reader">The System.IO.StringReader that contains the String to be parsed.</param>
            public StreamTokenizerSupport(System.IO.StringReader reader)
            {
                string s = "";
                for (int i = reader.Read(); i != -1; i = reader.Read())
                {
                    s += (char)i;
                }
                reader.Close();
                this.inStringReader = new BackStringReader(s);
                this.init();
            }

            /// <summary>
            /// Creates a StreamTokenizerSupport that parses the given stream.
            /// </summary>
            /// <param name="reader">Reader to be parsed.</param>
            public StreamTokenizerSupport(System.IO.StreamReader reader)
            {
                this.inReader = new BackReader(new System.IO.StreamReader(reader.BaseStream, reader.CurrentEncoding).BaseStream, 2, reader.CurrentEncoding);
                this.init();
            }

            /// <summary>
            /// Creates a StreamTokenizerSupport that parses the given stream.
            /// </summary>
            /// <param name="stream">Stream to be parsed.</param>
            public StreamTokenizerSupport(System.IO.Stream stream)
            {
                this.inStream = new BackInputStream(new System.IO.BufferedStream(stream), 2);
                this.init();
            }

            /// <summary>
            /// Specified that the character argument starts a single-line comment.
            /// </summary>
            /// <param name="ch">The character.</param>
            public virtual void CommentChar(int ch)
            {
                if (ch >= 0 && ch <= 255)
                    this.attribute[ch] = StreamTokenizerSupport.COMMENTCHAR;
            }

            /// <summary>
            /// Determines whether or not ends of line are treated as tokens.
            /// </summary>
            /// <param name="flag">True indicates that end-of-line characters are separate tokens; False indicates 
            /// that end-of-line characters are white space.</param>
            public virtual void EOLIsSignificant(bool flag)
            {
                this.eolIsSignificant = flag;
            }

            /// <summary>
            /// Return the current line number.
            /// </summary>
            /// <returns>Current line number</returns>
            public virtual int Lineno()
            {
                return this.lineno;
            }

            /// <summary>
            /// Determines whether or not word token are automatically lowercased.
            /// </summary>
            /// <param name="flag">True indicates that all word tokens should be lowercased.</param>
            public virtual void LowerCaseMode(bool flag)
            {
                this.lowerCaseMode = flag;
            }

            /// <summary>
            /// Parses the next token from the input stream of this tokenizer.
            /// </summary>
            /// <returns>The value of the ttype field.</returns>
            public virtual int NextToken()
            {
                char prevChar = (char)(0);
                char ch = (char)(0);
                char qChar = (char)(0);
                int octalNumber = 0;
                int state;

                if (this.pushedback)
                {
                    this.pushedback = false;
                    return this.ttype;
                }

                this.ttype = StreamTokenizerSupport.TT_NOTHING;
                state = StreamTokenizerSupport.STATE_NEUTRAL;
                this.nval = 0.0;
                this.sval = null;
                this.buf.Length = 0;

                do
                {
                    int data = this.read();
                    prevChar = ch;
                    ch = (char)data;

                    switch (state)
                    {
                        case StreamTokenizerSupport.STATE_NEUTRAL:
                            {
                                if (data == -1)
                                {
                                    this.ttype = TT_EOF;
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                else if (ch > 255)
                                {
                                    this.buf.Append(ch);
                                    this.ttype = StreamTokenizerSupport.TT_WORD;
                                    state = StreamTokenizerSupport.STATE_WORD;
                                }
                                else if (this.attribute[ch] == StreamTokenizerSupport.COMMENTCHAR)
                                {
                                    state = StreamTokenizerSupport.STATE_LINECOMMENT;
                                }
                                else if (this.attribute[ch] == StreamTokenizerSupport.WORDCHAR)
                                {
                                    this.buf.Append(ch);
                                    this.ttype = StreamTokenizerSupport.TT_WORD;
                                    state = StreamTokenizerSupport.STATE_WORD;
                                }
                                else if (this.attribute[ch] == StreamTokenizerSupport.NUMBERCHAR)
                                {
                                    this.ttype = StreamTokenizerSupport.TT_NUMBER;
                                    this.buf.Append(ch);
                                    if (ch == '-')
                                        state = StreamTokenizerSupport.STATE_NUMBER1;
                                    else if (ch == '.')
                                        state = StreamTokenizerSupport.STATE_NUMBER3;
                                    else
                                        state = StreamTokenizerSupport.STATE_NUMBER2;
                                }
                                else if (this.attribute[ch] == StreamTokenizerSupport.QUOTECHAR)
                                {
                                    qChar = ch;
                                    this.ttype = ch;
                                    state = StreamTokenizerSupport.STATE_STRING;
                                }
                                else if ((this.slashSlashComments || this.slashStarComments) && ch == '/')
                                    state = StreamTokenizerSupport.STATE_POSSIBLEC_COMMENT;
                                else if (this.attribute[ch] == StreamTokenizerSupport.ORDINARYCHAR)
                                {
                                    this.ttype = ch;
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                else if (ch == '\n' || ch == '\r')
                                {
                                    this.lineno++;
                                    if (this.eolIsSignificant)
                                    {
                                        this.ttype = StreamTokenizerSupport.TT_EOL;
                                        if (ch == '\n')
                                            state = StreamTokenizerSupport.STATE_DONE;
                                        else if (ch == '\r')
                                            state = StreamTokenizerSupport.STATE_DONE_ON_EOL;
                                    }
                                    else if (ch == '\r')
                                        state = StreamTokenizerSupport.STATE_PROCEED_ON_EOL;
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_WORD:
                            {
                                if (this.isWordChar(data))
                                    this.buf.Append(ch);
                                else
                                {
                                    if (data != -1)
                                        this.unread(ch);
                                    this.sval = this.buf.ToString();
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_NUMBER1:
                            {
                                if (data == -1 || this.attribute[ch] != StreamTokenizerSupport.NUMBERCHAR || ch == '-')
                                {
                                    if (this.attribute[ch] == StreamTokenizerSupport.COMMENTCHAR && System.Char.IsNumber(ch))
                                    {
                                        this.buf.Append(ch);
                                        state = StreamTokenizerSupport.STATE_NUMBER2;
                                    }
                                    else
                                    {
                                        if (data != -1)
                                            this.unread(ch);
                                        this.ttype = '-';
                                        state = StreamTokenizerSupport.STATE_DONE;
                                    }
                                }
                                else
                                {
                                    this.buf.Append(ch);
                                    if (ch == '.')
                                        state = StreamTokenizerSupport.STATE_NUMBER3;
                                    else
                                        state = StreamTokenizerSupport.STATE_NUMBER2;
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_NUMBER2:
                            {
                                if (data == -1 || this.attribute[ch] != StreamTokenizerSupport.NUMBERCHAR || ch == '-')
                                {
                                    if (System.Char.IsNumber(ch) && this.attribute[ch] == StreamTokenizerSupport.WORDCHAR)
                                    {
                                        this.buf.Append(ch);
                                    }
                                    else if (ch == '.' && this.attribute[ch] == StreamTokenizerSupport.WHITESPACECHAR)
                                    {
                                        this.buf.Append(ch);
                                    }

                                    else if ((data != -1) && (this.attribute[ch] == StreamTokenizerSupport.COMMENTCHAR && System.Char.IsNumber(ch)))
                                    {
                                        this.buf.Append(ch);
                                    }
                                    else
                                    {
                                        if (data != -1)
                                            this.unread(ch);
                                        try
                                        {
                                            this.nval = System.Double.Parse(this.buf.ToString());
                                        }
                                        catch (System.FormatException) { }
                                        state = StreamTokenizerSupport.STATE_DONE;
                                    }
                                }
                                else
                                {
                                    this.buf.Append(ch);
                                    if (ch == '.')
                                        state = StreamTokenizerSupport.STATE_NUMBER3;
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_NUMBER3:
                            {
                                if (data == -1 || this.attribute[ch] != StreamTokenizerSupport.NUMBERCHAR || ch == '-' || ch == '.')
                                {
                                    if (this.attribute[ch] == StreamTokenizerSupport.COMMENTCHAR && System.Char.IsNumber(ch))
                                    {
                                        this.buf.Append(ch);
                                    }
                                    else
                                    {
                                        if (data != -1)
                                            this.unread(ch);
                                        System.String str = this.buf.ToString();
                                        if (str.Equals(StreamTokenizerSupport.DASH))
                                        {
                                            this.unread('.');
                                            this.ttype = '-';
                                        }
                                        else if (str.Equals(StreamTokenizerSupport.DOT) && !(StreamTokenizerSupport.WORDCHAR != this.attribute[prevChar]))
                                            this.ttype = '.';
                                        else
                                        {
                                            try
                                            {
                                                this.nval = System.Double.Parse(str);
                                            }
                                            catch (System.FormatException) { }
                                        }
                                        state = StreamTokenizerSupport.STATE_DONE;
                                    }
                                }
                                else
                                {
                                    this.buf.Append(ch);
                                    state = StreamTokenizerSupport.STATE_NUMBER4;
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_NUMBER4:
                            {
                                if (data == -1 || this.attribute[ch] != StreamTokenizerSupport.NUMBERCHAR || ch == '-' || ch == '.')
                                {
                                    if (data != -1)
                                        this.unread(ch);
                                    try
                                    {
                                        this.nval = System.Double.Parse(this.buf.ToString());
                                    }
                                    catch (System.FormatException) { }
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                else
                                    this.buf.Append(ch);
                                break;
                            }
                        case StreamTokenizerSupport.STATE_LINECOMMENT:
                            {
                                if (data == -1)
                                {
                                    this.ttype = StreamTokenizerSupport.TT_EOF;
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                else if (ch == '\n' || ch == '\r')
                                {
                                    this.unread(ch);
                                    state = StreamTokenizerSupport.STATE_NEUTRAL;
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_DONE_ON_EOL:
                            {
                                if (ch != '\n' && data != -1)
                                    this.unread(ch);
                                state = StreamTokenizerSupport.STATE_DONE;
                                break;
                            }
                        case StreamTokenizerSupport.STATE_PROCEED_ON_EOL:
                            {
                                if (ch != '\n' && data != -1)
                                    this.unread(ch);
                                state = StreamTokenizerSupport.STATE_NEUTRAL;
                                break;
                            }
                        case StreamTokenizerSupport.STATE_STRING:
                            {
                                if (data == -1 || ch == qChar || ch == '\r' || ch == '\n')
                                {
                                    this.sval = this.buf.ToString();
                                    if (ch == '\r' || ch == '\n')
                                        this.unread(ch);
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                else if (ch == '\\')
                                    state = StreamTokenizerSupport.STATE_STRING_ESCAPE_SEQ;
                                else
                                    this.buf.Append(ch);
                                break;
                            }
                        case StreamTokenizerSupport.STATE_STRING_ESCAPE_SEQ:
                            {
                                if (data == -1)
                                {
                                    this.sval = this.buf.ToString();
                                    state = StreamTokenizerSupport.STATE_DONE;
                                    break;
                                }

                                state = StreamTokenizerSupport.STATE_STRING;
                                if (ch == 'a')
                                    this.buf.Append(0x7);
                                else if (ch == 'b')
                                    this.buf.Append('\b');
                                else if (ch == 'f')
                                    this.buf.Append(0xC);
                                else if (ch == 'n')
                                    this.buf.Append('\n');
                                else if (ch == 'r')
                                    this.buf.Append('\r');
                                else if (ch == 't')
                                    this.buf.Append('\t');
                                else if (ch == 'v')
                                    this.buf.Append(0xB);
                                else if (ch >= '0' && ch <= '7')
                                {
                                    octalNumber = ch - '0';
                                    state = StreamTokenizerSupport.STATE_STRING_ESCAPE_SEQ_OCTAL;
                                }
                                else
                                    this.buf.Append(ch);
                                break;
                            }
                        case StreamTokenizerSupport.STATE_STRING_ESCAPE_SEQ_OCTAL:
                            {
                                if (data == -1 || ch < '0' || ch > '7')
                                {
                                    this.buf.Append((char)octalNumber);
                                    if (data == -1)
                                    {
                                        this.sval = buf.ToString();
                                        state = StreamTokenizerSupport.STATE_DONE;
                                    }
                                    else
                                    {
                                        this.unread(ch);
                                        state = StreamTokenizerSupport.STATE_STRING;
                                    }
                                }
                                else
                                {
                                    int temp = octalNumber * 8 + (ch - '0');
                                    if (temp < 256)
                                        octalNumber = temp;
                                    else
                                    {
                                        buf.Append((char)octalNumber);
                                        buf.Append(ch);
                                        state = StreamTokenizerSupport.STATE_STRING;
                                    }
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_POSSIBLEC_COMMENT:
                            {
                                if (ch == '*')
                                    state = StreamTokenizerSupport.STATE_C_COMMENT;
                                else if (ch == '/')
                                    state = StreamTokenizerSupport.STATE_LINECOMMENT;
                                else
                                {
                                    if (data != -1)
                                        this.unread(ch);
                                    this.ttype = '/';
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_C_COMMENT:
                            {
                                if (ch == '*')
                                    state = StreamTokenizerSupport.STATE_POSSIBLEC_COMMENT_END;
                                if (ch == '\n')
                                    this.lineno++;
                                else if (data == -1)
                                {
                                    this.ttype = StreamTokenizerSupport.TT_EOF;
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                break;
                            }
                        case StreamTokenizerSupport.STATE_POSSIBLEC_COMMENT_END:
                            {
                                if (data == -1)
                                {
                                    this.ttype = StreamTokenizerSupport.TT_EOF;
                                    state = StreamTokenizerSupport.STATE_DONE;
                                }
                                else if (ch == '/')
                                    state = StreamTokenizerSupport.STATE_NEUTRAL;
                                else if (ch != '*')
                                    state = StreamTokenizerSupport.STATE_C_COMMENT;
                                break;
                            }
                    }
                }
                while (state != StreamTokenizerSupport.STATE_DONE);

                if (this.ttype == StreamTokenizerSupport.TT_WORD && this.lowerCaseMode)
                    this.sval = this.sval.ToLower();

                return this.ttype;
            }

            /// <summary>
            /// Specifies that the character argument is "ordinary" in this tokenizer.
            /// </summary>
            /// <param name="ch">The character.</param>
            public virtual void OrdinaryChar(int ch)
            {
                if (ch >= 0 && ch <= 255)
                    this.attribute[ch] = StreamTokenizerSupport.ORDINARYCHAR;
            }

            /// <summary>
            /// Specifies that all characters c in the range low less-equal c less-equal high are "ordinary" in this 
            /// tokenizer.
            /// </summary>
            /// <param name="low">Low end of the range.</param>
            /// <param name="hi">High end of the range.</param>
            public virtual void OrdinaryChars(int low, int hi)
            {
                this.setAttributes(low, hi, StreamTokenizerSupport.ORDINARYCHAR);
            }

            /// <summary>
            /// Specifies that numbers should be parsed by this tokenizer.
            /// </summary>
            public virtual void ParseNumbers()
            {
                for (int i = '0'; i <= '9'; i++)
                    this.attribute[i] = StreamTokenizerSupport.NUMBERCHAR;
                this.attribute['.'] = StreamTokenizerSupport.NUMBERCHAR;
                this.attribute['-'] = StreamTokenizerSupport.NUMBERCHAR;
            }

            /// <summary>
            /// Causes the next call to the nextToken method of this tokenizer to return the current value in the 
            /// ttype field, and not to modify the value in the nval or sval field.
            /// </summary>
            public virtual void PushBack()
            {
                if (this.ttype != StreamTokenizerSupport.TT_NOTHING)
                    this.pushedback = true;
            }

            /// <summary>
            /// Specifies that matching pairs of this character delimit string constants in this tokenizer.
            /// </summary>
            /// <param name="ch">The character.</param>
            public virtual void QuoteChar(int ch)
            {
                if (ch >= 0 && ch <= 255)
                    this.attribute[ch] = QUOTECHAR;
            }

            /// <summary>
            /// Resets this tokenizer's syntax table so that all characters are "ordinary." See the ordinaryChar 
            /// method for more information on a character being ordinary.
            /// </summary>
            public virtual void ResetSyntax()
            {
                this.OrdinaryChars(0x00, 0xff);
            }

            /// <summary>
            /// Determines whether or not the tokenizer recognizes C++-style comments.
            /// </summary>
            /// <param name="flag">True indicates to recognize and ignore C++-style comments.</param>
            public virtual void SlashSlashComments(bool flag)
            {
                this.slashSlashComments = flag;
            }

            /// <summary>
            /// Determines whether or not the tokenizer recognizes C-style comments.
            /// </summary>
            /// <param name="flag">True indicates to recognize and ignore C-style comments.</param>
            public virtual void SlashStarComments(bool flag)
            {
                this.slashStarComments = flag;
            }

            /// <summary>
            /// Returns the string representation of the current stream token.
            /// </summary>
            /// <returns>A String representation of the current stream token.</returns>
            public override System.String ToString()
            {
                System.Text.StringBuilder buffer = new System.Text.StringBuilder(StreamTokenizerSupport.TOKEN);

                switch (this.ttype)
                {
                    case StreamTokenizerSupport.TT_NOTHING:
                        {
                            buffer.Append(StreamTokenizerSupport.NOTHING);
                            break;
                        }
                    case StreamTokenizerSupport.TT_WORD:
                        {
                            buffer.Append(this.sval);
                            break;
                        }
                    case StreamTokenizerSupport.TT_NUMBER:
                        {
                            buffer.Append(StreamTokenizerSupport.NUMBER);
                            buffer.Append(this.nval);
                            break;
                        }
                    case StreamTokenizerSupport.TT_EOF:
                        {
                            buffer.Append(StreamTokenizerSupport.EOF);
                            break;
                        }
                    case StreamTokenizerSupport.TT_EOL:
                        {
                            buffer.Append(StreamTokenizerSupport.EOL);
                            break;
                        }
                }

                if (this.ttype > 0)
                {
                    if (this.attribute[this.ttype] == StreamTokenizerSupport.QUOTECHAR)
                    {
                        buffer.Append(StreamTokenizerSupport.QUOTED);
                        buffer.Append(this.sval);
                    }
                    else
                    {
                        buffer.Append('\'');
                        buffer.Append((char)this.ttype);
                        buffer.Append('\'');
                    }
                }

                buffer.Append(StreamTokenizerSupport.LINE);
                buffer.Append(this.lineno);
                return buffer.ToString();
            }

            /// <summary>
            /// Specifies that all characters c in the range low less-equal c less-equal high are white space 
            /// characters.
            /// </summary>
            /// <param name="low">The low end of the range.</param>
            /// <param name="hi">The high end of the range.</param>
            public virtual void WhitespaceChars(int low, int hi)
            {
                this.setAttributes(low, hi, StreamTokenizerSupport.WHITESPACECHAR);
            }

            /// <summary>
            /// Specifies that all characters c in the range low less-equal c less-equal high are word constituents.
            /// </summary>
            /// <param name="low">The low end of the range.</param>
            /// <param name="hi">The high end of the range.</param>
            public virtual void WordChars(int low, int hi)
            {
                this.setAttributes(low, hi, StreamTokenizerSupport.WORDCHAR);
            }
        }


        /*******************************/
        /// <summary>
        /// Receives a byte array and returns it transformed in an sbyte array
        /// </summary>
        /// <param name="byteArray">Byte array to process</param>
        /// <returns>The transformed array</returns>
        public static sbyte[] ToSByteArray(byte[] byteArray)
        {
            sbyte[] sbyteArray = null;
            if (byteArray != null)
            {
                sbyteArray = new sbyte[byteArray.Length];
                for (int index = 0; index < byteArray.Length; index++)
                    sbyteArray[index] = (sbyte)byteArray[index];
            }
            return sbyteArray;
        }

        /*******************************/
        /// <summary>
        /// This class provides functionality to reads and unread characters into a buffer.
        /// </summary>
        public class BackReader : System.IO.StreamReader
        {
            private char[] buffer;
            private int position = 1;
            //private int markedPosition;

            /// <summary>
            /// Constructor. Calls the base constructor.
            /// </summary>
            /// <param name="streamReader">The buffer from which chars will be read.</param>
            /// <param name="size">The size of the Back buffer.</param>
            public BackReader(System.IO.Stream streamReader, int size, System.Text.Encoding encoding)
                : base(streamReader, encoding)
            {
                this.buffer = new char[size];
                this.position = size;
            }

            /// <summary>
            /// Constructor. Calls the base constructor.
            /// </summary>
            /// <param name="streamReader">The buffer from which chars will be read.</param>
            public BackReader(System.IO.Stream streamReader, System.Text.Encoding encoding)
                : base(streamReader, encoding)
            {
                this.buffer = new char[this.position];
            }

            /// <summary>
            /// Checks if this stream support mark and reset methods.
            /// </summary>
            /// <remarks>
            /// This method isn't supported.
            /// </remarks>
            /// <returns>Always false.</returns>
            public bool MarkSupported()
            {
                return false;
            }

            /// <summary>
            /// Marks the element at the corresponding position.
            /// </summary>
            /// <remarks>
            /// This method isn't supported.
            /// </remarks>
            public void Mark(int position)
            {
                throw new System.IO.IOException("Mark operations are not allowed");
            }

            /// <summary>
            /// Resets the current stream.
            /// </summary>
            /// <remarks>
            /// This method isn't supported.
            /// </remarks>
            public void Reset()
            {
                throw new System.IO.IOException("Mark operations are not allowed");
            }

            /// <summary>
            /// Reads a character.
            /// </summary>
            /// <returns>The character read.</returns>
            public override int Read()
            {
                if (this.position >= 0 && this.position < this.buffer.Length)
                    return (int)this.buffer[this.position++];
                return base.Read();
            }

            /// <summary>
            /// Reads an amount of characters from the buffer and copies the values to the array passed.
            /// </summary>
            /// <param name="array">Array where the characters will be stored.</param>
            /// <param name="index">The beginning index to read.</param>
            /// <param name="count">The number of characters to read.</param>
            /// <returns>The number of characters read.</returns>
            public override int Read(char[] array, int index, int count)
            {
                int readLimit = this.buffer.Length - this.position;

                if (count <= 0)
                    return 0;

                if (readLimit > 0)
                {
                    if (count < readLimit)
                        readLimit = count;
                    System.Array.Copy(this.buffer, this.position, array, index, readLimit);
                    count -= readLimit;
                    index += readLimit;
                    this.position += readLimit;
                }

                if (count > 0)
                {
                    count = base.Read(array, index, count);
                    if (count == -1)
                    {
                        if (readLimit == 0)
                            return -1;
                        return readLimit;
                    }
                    return readLimit + count;
                }
                return readLimit;
            }

            /// <summary>
            /// Checks if this buffer is ready to be read.
            /// </summary>
            /// <returns>True if the position is less than the length, otherwise false.</returns>
            public bool IsReady()
            {
                return (this.position >= this.buffer.Length || this.BaseStream.Position >= this.BaseStream.Length);
            }

            /// <summary>
            /// Unreads a character.
            /// </summary>
            /// <param name="unReadChar">The character to be unread.</param>
            public void UnRead(int unReadChar)
            {
                this.position--;
                this.buffer[this.position] = (char)unReadChar;
            }

            /// <summary>
            /// Unreads an amount of characters by moving these to the buffer.
            /// </summary>
            /// <param name="array">The character array to be unread.</param>
            /// <param name="index">The beginning index to unread.</param>
            /// <param name="count">The number of characters to unread.</param>
            public void UnRead(char[] array, int index, int count)
            {
                this.Move(array, index, count);
            }

            /// <summary>
            /// Unreads an amount of characters by moving these to the buffer.
            /// </summary>
            /// <param name="array">The character array to be unread.</param>
            public void UnRead(char[] array)
            {
                this.Move(array, 0, array.Length - 1);
            }

            /// <summary>
            /// Moves the array of characters to the buffer.
            /// </summary>
            /// <param name="array">Array of characters to move.</param>
            /// <param name="index">Offset of the beginning.</param>
            /// <param name="count">Amount of characters to move.</param>
            private void Move(char[] array, int index, int count)
            {
                for (int arrayPosition = index + count; arrayPosition >= index; arrayPosition--)
                    this.UnRead(array[arrayPosition]);
            }
        }


        /*******************************/
        /// <summary>
        /// Provides functionality to read and unread from a Stream.
        /// </summary>
        public class BackInputStream : System.IO.BinaryReader
        {
            private byte[] buffer;
            private int position = 1;

            /// <summary>
            /// Creates a BackInputStream with the specified stream and size for the buffer.
            /// </summary>
            /// <param name="streamReader">The stream to use.</param>
            /// <param name="size">The specific size of the buffer.</param>
            public BackInputStream(System.IO.Stream streamReader, System.Int32 size)
                : base(streamReader)
            {
                this.buffer = new byte[size];
                this.position = size;
            }

            /// <summary>
            /// Creates a BackInputStream with the specified stream.
            /// </summary>
            /// <param name="streamReader">The stream to use.</param>
            public BackInputStream(System.IO.Stream streamReader)
                : base(streamReader)
            {
                this.buffer = new byte[this.position];
            }

            /// <summary>
            /// Checks if this stream support mark and reset methods.
            /// </summary>
            /// <returns>Always false, these methods aren't supported.</returns>
            public bool MarkSupported()
            {
                return false;
            }

            /// <summary>
            /// Reads the next bytes in the stream.
            /// </summary>
            /// <returns>The next byte readed</returns>
            public override int Read()
            {
                if (position >= 0 && position < buffer.Length)
                    return (int)this.buffer[position++];
                return base.Read();
            }

            /// <summary>
            /// Reads the amount of bytes specified from the stream.
            /// </summary>
            /// <param name="array">The buffer to read data into.</param>
            /// <param name="index">The beginning point to read.</param>
            /// <param name="count">The number of characters to read.</param>
            /// <returns>The number of characters read into buffer.</returns>
            public virtual int Read(sbyte[] array, int index, int count)
            {
                int byteCount = 0;
                int readLimit = count + index;
                byte[] aux = ToByteArray(array);

                for (byteCount = 0; position < buffer.Length && index < readLimit; byteCount++)
                    aux[index++] = buffer[position++];

                if (index < readLimit)
                    byteCount += base.Read(aux, index, readLimit - index);

                for (int i = 0; i < aux.Length; i++)
                    array[i] = (sbyte)aux[i];

                return byteCount;
            }

            /// <summary>
            /// Unreads a byte from the stream.
            /// </summary>
            /// <param name="element">The value to be unread.</param>
            public void UnRead(int element)
            {
                this.position--;
                if (position >= 0)
                    this.buffer[this.position] = (byte)element;
            }

            /// <summary>
            /// Unreads an amount of bytes from the stream.
            /// </summary>
            /// <param name="array">The byte array to be unread.</param>
            /// <param name="index">The beginning index to unread.</param>
            /// <param name="count">The number of bytes to be unread.</param>
            public void UnRead(byte[] array, int index, int count)
            {
                this.Move(array, index, count);
            }

            /// <summary>
            /// Unreads an array of bytes from the stream.
            /// </summary>
            /// <param name="array">The byte array to be unread.</param>
            public void UnRead(byte[] array)
            {
                this.Move(array, 0, array.Length - 1);
            }

            /// <summary>
            /// Skips the specified number of bytes from the underlying stream.
            /// </summary>
            /// <param name="numberOfBytes">The number of bytes to be skipped.</param>
            /// <returns>The number of bytes actually skipped</returns>
            public long Skip(long numberOfBytes)
            {
                return this.BaseStream.Seek(numberOfBytes, System.IO.SeekOrigin.Current) - this.BaseStream.Position;
            }

            /// <summary>
            /// Moves data from the array to the buffer field.
            /// </summary>
            /// <param name="array">The array of bytes to be unread.</param>
            /// <param name="index">The beginning index to unread.</param>
            /// <param name="count">The amount of bytes to be unread.</param>
            private void Move(byte[] array, int index, int count)
            {
                for (int arrayPosition = index + count; arrayPosition >= index; arrayPosition--)
                    this.UnRead(array[arrayPosition]);
            }
        }


        /*******************************/
        /// <summary>
        /// Implements number format functions
        /// </summary>
        [Serializable]
        public class TextNumberFormat
        {

            //Current localization number format infomation
            private System.Globalization.NumberFormatInfo numberFormat;
            //Enumeration of format types that can be used
            private enum formatTypes { General, Number, Currency, Percent };
            //Current format type used in the instance
            private int numberFormatType;
            //Indicates if grouping is being used
            private bool groupingActivated;
            //Current separator used
            private System.String separator;
            //Number of maximun digits in the integer portion of the number to represent the number
            private int maxIntDigits;
            //Number of minimum digits in the integer portion of the number to represent the number
            private int minIntDigits;
            //Number of maximun digits in the fraction portion of the number to represent the number
            private int maxFractionDigits;
            //Number of minimum digits in the integer portion of the number to represent the number
            private int minFractionDigits;

            /// <summary>
            /// Initializes a new instance of the object class with the default values
            /// </summary>
            public TextNumberFormat()
            {
                this.numberFormat = new System.Globalization.NumberFormatInfo();
                this.numberFormatType = (int)TextNumberFormat.formatTypes.General;
                this.groupingActivated = true;
                this.separator = this.GetSeparator((int)TextNumberFormat.formatTypes.General);
                this.maxIntDigits = 127;
                this.minIntDigits = 1;
                this.maxFractionDigits = 3;
                this.minFractionDigits = 0;
            }

            /// <summary>
            /// Sets the Maximum integer digits value. 
            /// </summary>
            /// <param name="newValue">the new value for the maxIntDigits field</param>
            public void setMaximumIntegerDigits(int newValue)
            {
                maxIntDigits = newValue;
                if (newValue <= 0)
                {
                    maxIntDigits = 0;
                    minIntDigits = 0;
                }
                else if (maxIntDigits < minIntDigits)
                {
                    minIntDigits = maxIntDigits;
                }
            }

            /// <summary>
            /// Sets the minimum integer digits value. 
            /// </summary>
            /// <param name="newValue">the new value for the minIntDigits field</param>
            public void setMinimumIntegerDigits(int newValue)
            {
                minIntDigits = newValue;
                if (newValue <= 0)
                {
                    minIntDigits = 0;
                }
                else if (maxIntDigits < minIntDigits)
                {
                    maxIntDigits = minIntDigits;
                }
            }

            /// <summary>
            /// Sets the maximum fraction digits value. 
            /// </summary>
            /// <param name="newValue">the new value for the maxFractionDigits field</param>
            public void setMaximumFractionDigits(int newValue)
            {
                maxFractionDigits = newValue;
                if (newValue <= 0)
                {
                    maxFractionDigits = 0;
                    minFractionDigits = 0;
                }
                else if (maxFractionDigits < minFractionDigits)
                {
                    minFractionDigits = maxFractionDigits;
                }
            }

            /// <summary>
            /// Sets the minimum fraction digits value. 
            /// </summary>
            /// <param name="newValue">the new value for the minFractionDigits field</param>
            public void setMinimumFractionDigits(int newValue)
            {
                minFractionDigits = newValue;
                if (newValue <= 0)
                {
                    minFractionDigits = 0;
                }
                else if (maxFractionDigits < minFractionDigits)
                {
                    maxFractionDigits = minFractionDigits;
                }
            }

            /// <summary>
            /// Initializes a new instance of the class with the specified number format
            /// and the amount of fractional digits to use
            /// </summary>
            /// <param name="theType">Number format</param>
            /// <param name="digits">Number of fractional digits to use</param>
            private TextNumberFormat(TextNumberFormat.formatTypes theType, int digits)
            {
                this.numberFormat = System.Globalization.NumberFormatInfo.CurrentInfo;
                this.numberFormatType = (int)theType;
                this.groupingActivated = true;
                this.separator = this.GetSeparator((int)theType);
                this.maxIntDigits = 127;
                this.minIntDigits = 1;
                this.maxFractionDigits = 3;
                this.minFractionDigits = 0;
            }

            /// <summary>
            /// Initializes a new instance of the class with the specified number format,
            /// uses the system's culture information,
            /// and assigns the amount of fractional digits to use
            /// </summary>
            /// <param name="theType">Number format</param>
            /// <param name="cultureNumberFormat">Represents information about a specific culture including the number formatting</param>
            /// <param name="digits">Number of fractional digits to use</param>
            private TextNumberFormat(TextNumberFormat.formatTypes theType, System.Globalization.CultureInfo cultureNumberFormat, int digits)
            {
                this.numberFormat = cultureNumberFormat.NumberFormat;
                this.numberFormatType = (int)theType;
                this.groupingActivated = true;
                this.separator = this.GetSeparator((int)theType);
                this.maxIntDigits = 127;
                this.minIntDigits = 1;
                this.maxFractionDigits = 3;
                this.minFractionDigits = 0;
            }

            /// <summary>
            /// Returns an initialized instance of the TextNumberFormat object
            /// using number representation.
            /// </summary>
            /// <returns>The object instance</returns>
            public static TextNumberFormat getTextNumberInstance()
            {
                TextNumberFormat instance = new TextNumberFormat(TextNumberFormat.formatTypes.Number, 3);
                return instance;
            }

            /// <summary>
            /// Returns an initialized instance of the TextNumberFormat object
            /// using currency representation.
            /// </summary>
            /// <returns>The object instance</returns>
            public static TextNumberFormat getTextNumberCurrencyInstance()
            {
                TextNumberFormat instance = new TextNumberFormat(TextNumberFormat.formatTypes.Currency, 3);
                return instance.setToCurrencyNumberFormatDefaults(instance);
            }

            /// <summary>
            /// Returns an initialized instance of the TextNumberFormat object
            /// using percent representation.
            /// </summary>
            /// <returns>The object instance</returns>
            public static TextNumberFormat getTextNumberPercentInstance()
            {
                TextNumberFormat instance = new TextNumberFormat(TextNumberFormat.formatTypes.Percent, 3);
                return instance.setToPercentNumberFormatDefaults(instance);
            }

            /// <summary>
            /// Returns an initialized instance of the TextNumberFormat object
            /// using number representation, it uses the culture format information provided.
            /// </summary>
            /// <param name="culture">Represents information about a specific culture</param>
            /// <returns>The object instance</returns>
            public static TextNumberFormat getTextNumberInstance(System.Globalization.CultureInfo culture)
            {
                TextNumberFormat instance = new TextNumberFormat(TextNumberFormat.formatTypes.Number, culture, 3);
                return instance;
            }

            /// <summary>
            /// Returns an initialized instance of the TextNumberFormat object
            /// using currency representation, it uses the culture format information provided.
            /// </summary>
            /// <param name="culture">Represents information about a specific culture</param>
            /// <returns>The object instance</returns>
            public static TextNumberFormat getTextNumberCurrencyInstance(System.Globalization.CultureInfo culture)
            {
                TextNumberFormat instance = new TextNumberFormat(TextNumberFormat.formatTypes.Currency, culture, 3);
                return instance.setToCurrencyNumberFormatDefaults(instance);
            }

            /// <summary>
            /// Returns an initialized instance of the TextNumberFormat object
            /// using percent representation, it uses the culture format information provided.
            /// </summary>
            /// <param name="culture">Represents information about a specific culture</param>
            /// <returns>The object instance</returns>
            public static TextNumberFormat getTextNumberPercentInstance(System.Globalization.CultureInfo culture)
            {
                TextNumberFormat instance = new TextNumberFormat(TextNumberFormat.formatTypes.Percent, culture, 3);
                return instance.setToPercentNumberFormatDefaults(instance);
            }

            /// <summary>
            /// Clones the object instance
            /// </summary>
            /// <returns>The cloned object instance</returns>
            public System.Object Clone()
            {
                return (System.Object)this;
            }

            /// <summary>
            /// Determines if the received object is equal to the
            /// current object instance
            /// </summary>
            /// <param name="textNumberObject">TextNumber instance to compare</param>
            /// <returns>True or false depending if the two instances are equal</returns>
            public override bool Equals(Object obj)
            {
                // Check for null values and compare run-time types.
                if (obj == null || GetType() != obj.GetType())
                    return false;
                SupportClass.TextNumberFormat param = (SupportClass.TextNumberFormat)obj;
                return (numberFormat == param.numberFormat) && (numberFormatType == param.numberFormatType)
                    && (groupingActivated == param.groupingActivated) && (separator == param.separator)
                    && (maxIntDigits == param.maxIntDigits) && (minIntDigits == param.minIntDigits)
                    && (maxFractionDigits == param.maxFractionDigits) && (minFractionDigits == param.minFractionDigits);
            }


            /// <summary>
            /// Serves as a hash function for a particular type, suitable for use in hashing algorithms and data structures like a hash table.
            /// </summary>
            /// <returns>A hash code for the current Object</returns>
            public override int GetHashCode()
            {
                return numberFormat.GetHashCode() ^ numberFormatType ^ groupingActivated.GetHashCode()
                     ^ separator.GetHashCode() ^ maxIntDigits ^ minIntDigits ^ maxFractionDigits ^ minFractionDigits;
            }

            /// <summary>
            /// Formats a number with the current formatting parameters
            /// </summary>
            /// <param name="number">Source number to format</param>
            /// <returns>The formatted number string</returns>
            public System.String FormatDouble(double number)
            {
                if (this.groupingActivated)
                {
                    return SetIntDigits(number.ToString(this.GetCurrentFormatString() + this.GetNumberOfDigits(number), this.numberFormat));
                }
                else
                {
                    return SetIntDigits((number.ToString(this.GetCurrentFormatString() + this.GetNumberOfDigits(number), this.numberFormat)).Replace(this.separator, ""));
                }
            }

            /// <summary>
            /// Formats a number with the current formatting parameters
            /// </summary>
            /// <param name="number">Source number to format</param>
            /// <returns>The formatted number string</returns>
            public System.String FormatLong(long number)
            {
                if (this.groupingActivated)
                {
                    return SetIntDigits(number.ToString(this.GetCurrentFormatString() + this.minFractionDigits, this.numberFormat));
                }
                else
                {
                    return SetIntDigits((number.ToString(this.GetCurrentFormatString() + this.minFractionDigits, this.numberFormat)).Replace(this.separator, ""));
                }
            }


            /// <summary>
            /// Formats the number according to the specified number of integer digits 
            /// </summary>
            /// <param name="number">The number to format</param>
            /// <returns></returns>
            private System.String SetIntDigits(String number)
            {
                String decimals = "";
                String fraction = "";
                int i = number.IndexOf(this.numberFormat.NumberDecimalSeparator);
                if (i > 0)
                {
                    fraction = number.Substring(i);
                    decimals = number.Substring(0, i).Replace(this.numberFormat.NumberGroupSeparator, "");
                }
                else decimals = number.Replace(this.numberFormat.NumberGroupSeparator, "");
                decimals = decimals.PadLeft(this.MinIntDigits, '0');
                if ((i = decimals.Length - this.MaxIntDigits) > 0) decimals = decimals.Remove(0, i);
                if (this.groupingActivated)
                {
                    for (i = decimals.Length; i > 3; i -= 3)
                    {
                        decimals = decimals.Insert(i - 3, this.numberFormat.NumberGroupSeparator);
                    }
                }
                decimals = decimals + fraction;
                if (decimals.Length == 0) return "0";
                else return decimals;
            }

            /// <summary>
            /// Gets the list of all supported cultures
            /// </summary>
            /// <returns>An array of type CultureInfo that represents the supported cultures</returns>
            public static System.Globalization.CultureInfo[] GetAvailableCultures()
            {
                return System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.AllCultures);
            }

            /// <summary>
            /// Obtains the current format representation used
            /// </summary>
            /// <returns>A character representing the string format used</returns>
            private System.String GetCurrentFormatString()
            {
                System.String currentFormatString = "n";  //Default value
                switch (this.numberFormatType)
                {
                    case (int)TextNumberFormat.formatTypes.Currency:
                        currentFormatString = "c";
                        break;

                    case (int)TextNumberFormat.formatTypes.General:
                        currentFormatString = "n";
                        break;

                    case (int)TextNumberFormat.formatTypes.Number:
                        currentFormatString = "n";
                        break;

                    case (int)TextNumberFormat.formatTypes.Percent:
                        currentFormatString = "p";
                        break;
                }
                return currentFormatString;
            }

            /// <summary>
            /// Retrieves the separator used, depending on the format type specified
            /// </summary>
            /// <param name="numberFormatType">formatType enumarator value to inquire</param>
            /// <returns>The values of character separator used </returns>
            private System.String GetSeparator(int numberFormatType)
            {
                System.String separatorItem = " ";  //Default Separator

                switch (numberFormatType)
                {
                    case (int)TextNumberFormat.formatTypes.Currency:
                        separatorItem = this.numberFormat.CurrencyGroupSeparator;
                        break;

                    case (int)TextNumberFormat.formatTypes.General:
                        separatorItem = this.numberFormat.NumberGroupSeparator;
                        break;

                    case (int)TextNumberFormat.formatTypes.Number:
                        separatorItem = this.numberFormat.NumberGroupSeparator;
                        break;

                    case (int)TextNumberFormat.formatTypes.Percent:
                        separatorItem = this.numberFormat.PercentGroupSeparator;
                        break;
                }
                return separatorItem;
            }

            /// <summary>
            /// Boolean value stating if grouping is used or not
            /// </summary>
            public bool GroupingUsed
            {
                get
                {
                    return (this.groupingActivated);
                }
                set
                {
                    this.groupingActivated = value;
                }
            }

            /// <summary>
            /// Minimum number of integer digits to use in the number format
            /// </summary>
            public int MinIntDigits
            {
                get
                {
                    return this.minIntDigits;
                }
                set
                {
                    this.minIntDigits = value;
                }
            }

            /// <summary>
            /// Maximum number of integer digits to use in the number format
            /// </summary>
            public int MaxIntDigits
            {
                get
                {
                    return this.maxIntDigits;
                }
                set
                {
                    this.maxIntDigits = value;
                }
            }

            /// <summary>
            /// Minimum number of fraction digits to use in the number format
            /// </summary>
            public int MinFractionDigits
            {
                get
                {
                    return this.minFractionDigits;
                }
                set
                {
                    this.minFractionDigits = value;
                }
            }

            /// <summary>
            /// Maximum number of fraction digits to use in the number format
            /// </summary>
            public int MaxFractionDigits
            {
                get
                {
                    return this.maxFractionDigits;
                }
                set
                {
                    this.maxFractionDigits = value;
                }
            }

            /// <summary>
            /// Sets the values of minFractionDigits and maxFractionDigits to the currency standard
            /// </summary>
            /// <param name="format">The TextNumberFormat instance to set</param>
            /// <returns>The TextNumberFormat with corresponding the default values</returns>
            private TextNumberFormat setToCurrencyNumberFormatDefaults(TextNumberFormat format)
            {
                format.maxFractionDigits = 2;
                format.minFractionDigits = 2;
                return format;
            }

            /// <summary>
            /// Sets the values of minFractionDigits and maxFractionDigits to the percent standard
            /// </summary>
            /// <param name="format">The TextNumberFormat instance to set</param>
            /// <returns>The TextNumberFormat with corresponding the default values</returns>
            private TextNumberFormat setToPercentNumberFormatDefaults(TextNumberFormat format)
            {
                format.maxFractionDigits = 0;
                format.minFractionDigits = 0;
                return format;
            }

            /// <summary>
            /// Gets the number of fraction digits thats must be used by the format methods
            /// </summary>
            /// <param name="number">The double number</param>
            /// <returns>The number of fraction digits to use</returns>
            private int GetNumberOfDigits(Double number)
            {
                int counter = 0;
                double temp = System.Math.Abs(number);
                while ((temp % 1) > 0)
                {
                    temp *= 10;
                    counter++;
                }
                return (counter < this.minFractionDigits) ? this.minFractionDigits : ((counter < this.maxFractionDigits) ? counter : this.maxFractionDigits);
            }
        }
        /*******************************/
        /// <summary>
        /// Writes the exception stack trace to the received stream
        /// </summary>
        /// <param name="throwable">Exception to obtain information from</param>
        /// <param name="stream">Output sream used to write to</param>
        public static void WriteStackTrace(System.Exception throwable, System.IO.TextWriter stream)
        {
            stream.Write(throwable.StackTrace);
            stream.Flush();
        }

    }
}
